﻿
using System.Windows.Forms;
using Mapenect.KinectInterface;
using Mapenect.Data;
using System.Threading;
using OpenNI;
using Mapenect.GesturePatterns;
using Mapenect.GestureInterpreter;
using System.Collections.Generic;
using Mapenect.Database;
using System.Runtime.InteropServices;

namespace Mapenect
{
    class Controller
    {
        private FmMain gui;
        private MotorControl motorCont;
        private DataRetriever dataRet;
        private DataContainer jointDataCollection;
        private List<Gesture> knownGestures;
        private IDatabase db;


        public Controller(FmMain gui, PictureBox picFrame)
        {
            this.gui = gui;
            this.jointDataCollection = new DataContainer();
            this.dataRet = new DataRetriever(picFrame, jointDataCollection);
            this.motorCont = new MotorControl();

            if (!motorCont.Initialize())
            {
                gui.WriteToLog("Motor konnte nicht initialisiert werden.");
                gui.LockGui();
            }
            else if (!dataRet.initializeOpenNI())
            {
                gui.WriteToLog("OpenNI konnte nicht initialisiert werden.");
                gui.LockGui();
            }
            else
            {
                // Log registrieren
                dataRet.LogCalibPoseDetected += new Mapenect.KinectInterface.DataRetriever.LogEventHandler(logCalibPoseDetected);
                dataRet.LogSkeletonCalibrationEnded += new DataRetriever.LogEventHandler(dataRet_LogSkeletonCalibrationEnded);
                dataRet.LogSkeletonCalibrationStarted += new DataRetriever.LogEventHandler(dataRet_LogSkeletonCalibrationStarted);
                dataRet.LogUserLost += new DataRetriever.LogEventHandler(dataRet_LogUserLost);
                dataRet.LogNewUser += new DataRetriever.LogEventHandler(dataRet_LogNewUser);

                // db initialisieren
                db = new DatabaseController();
                this.LoadGestures();
            }
        }

        #region MotorControls

        public void IncreaseMotorPosition()
        {
            if (!motorCont.MoveUp())
            {
                gui.WriteToLog("Motor konnte nicht angesteuert werden. (Position erhöhen)");
                gui.Close();
            }
        }

        public void DecreaseMotorPosition()
        {
            if (!motorCont.MoveDown())
            {
                gui.WriteToLog("Motor konnte nicht angesteuert werden. (Position verringern)");
                gui.Close();
            }
        }

        public void ResetMotorPosition()
        {
            if (!motorCont.ResetPosition())
            {
                gui.WriteToLog("Motor konnte nicht angesteuert werden. (0-Position)");
                gui.Close();
            }
        }

        #endregion

        #region OpenNI Controls

        internal void SetCapturingMode(string mode)
        {
            dataRet.setCapturingMode(mode);
        }

        #endregion

        #region log

        private void logCalibPoseDetected(object sender, LogEventArgs e)
        {
            gui.WriteToLog("Calibrationpose " + e.Pose + " detected for User: " + e.UserId);
        }

        void dataRet_LogSkeletonCalibrationEnded(object sender, LogEventArgs e)
        {
            gui.WriteToLog("Skeletoncalibration ended for User: " + e.UserId + "; Success: " + e.Success);
        }

        void dataRet_LogSkeletonCalibrationStarted(object sender, LogEventArgs e)
        {
            gui.WriteToLog("Skeletoncalibration started for User: " + e.UserId);
        }

        void dataRet_LogUserLost(object sender, LogEventArgs e)
        {
            gui.WriteToLog("user_LostUser Callback... User: " + e.UserId);
        }

        void dataRet_LogNewUser(object sender, LogEventArgs e)
        {
            gui.WriteToLog("user_NewUser Callback... User: " + e.UserId);
        }

        #endregion

        #region Database Controls

        internal void SaveGesture(string name)
        {
            if (db.Connect())
            {

                Dictionary<SkeletonJoint, FixedQueueList<MyJoint>> list = jointDataCollection.getUserData(user.user1);

                Gesture gestureToAdd = new Gesture(name, list);
                knownGestures.Add(gestureToAdd);
                db.StoreGesture(gestureToAdd);
                gui.WriteToLog("Geste " + name + " wurde hinzugefügt.");
                db.Disconnect();
            }
            else
            {
                gui.WriteToLog("Geste konnte nicht gespeichert werden.");
            }
        }

        //internal void SaveGestures()
        //{
        //    if (db.Connect())
        //    {
        //        foreach (Gesture gest in knownGestures)
        //        {
        //            db.StoreGesture(gest);
        //        }
        //        gui.WriteToLog("Gestenliste in Datenbank gespeichert.");
        //        db.Disconnect();
        //    }
        //    else
        //    {
        //        gui.WriteToLog("Gestenliste konnte nicht gespeichert werden.");
        //    }
        //}

        private void LoadGestures()
        {
            if (db.Connect())
            {
                knownGestures = db.ReadGestures();
                foreach (Gesture gest in knownGestures)
                {
                    gui.WriteToLog("Gestenname: " + gest.Type);
                }

                gui.WriteToLog("Gesten wurden aus der Datenbank geladen.");
                db.Disconnect();
            }
            else
            {
                gui.WriteToLog("Gesten konnten nicht geladen werden.");
            }

        }

        #endregion

        public void DisbandController()
        {

            //this.SaveGestures();

            if (!motorCont.DisbandMotor())
            {
                MessageBox.Show("Motor konnte nicht korrekt beendet werden.");
            }

            if (!dataRet.StopRetrievingData())
            {
                MessageBox.Show("OpenNÍ konnte nicht korrekt beendet werden.");
            }
        }

        #region Erkennungs- und Zeitanzeige

        List<Interpreter> interp;
        Interpreter musicFun;

        internal void StartTest()
        {
            interp = new List<Interpreter>();
            Interpreter i;
            //Interpreter i = new PreInterpreter1(jointDataCollection, 0.1f);
            //i.GestureDetected += new Interpreter.GestureEventhandler(VectMetr_GestureDetected);
            //interp.Add(i);
            //i.Start();
            //i = new DistanceMetricInterpreter(jointDataCollection, knownGestures[0], 0.1f);
            //i.GestureDetected += new Interpreter.GestureEventhandler(Dist_GestureDetected);
            //interp.Add(i);
            //i.Start();
            i = new DistanceAngleMetricInterpreter(jointDataCollection, knownGestures[0], 0.2f);
            i.GestureDetected += new Interpreter.GestureEventhandler(beep1_GestureDetected);
            interp.Add(i);
            i.Start();
            i = new DistanceAngleMetricInterpreter(jointDataCollection, knownGestures[1], 0.4f);
            i.GestureDetected += new Interpreter.GestureEventhandler(beep2_GestureDetected);
            interp.Add(i);
            i.Start();
            i = new DistanceAngleMetricInterpreter(jointDataCollection, knownGestures[2], 0.2f);
            i.GestureDetected += new Interpreter.GestureEventhandler(beep3_GestureDetected);
            interp.Add(i);
            i.Start();
            musicFun = new SoundInterpreter(jointDataCollection, 0f);
        }

        void Angle_GestureDetected(object sender, System.EventArgs e)
        {
            gui.setAngleLabel(((Interpreter)sender).elapsedMilliSeconds.ToString());
            gui.WriteToLog("WinkelInterpreter !");
        }

        void Dist_GestureDetected(object sender, System.EventArgs e)
        {
            gui.setDistLabel(((Interpreter)sender).elapsedMilliSeconds.ToString());
            gui.WriteToLog("DistanzInterpreter");
        }

        void VectMetr_GestureDetected(object sender, System.EventArgs e)
        {
            gui.setVectMetrLabel(((Interpreter)sender).elapsedMilliSeconds.ToString());
            gui.WriteToLog("VektorInterpreter");
        }

        [DllImport("kernel32.dll")]
        public static extern bool Beep(int Frequenz, int Dauer);
        void beep1_GestureDetected(object sender, System.EventArgs e)
        {
            //Beep(1000, 1000);
            musicFun.Start();
        }

        void beep2_GestureDetected(object sender, System.EventArgs e)
        {
            //Beep(650, 500);
        }

        void beep3_GestureDetected(object sender, System.EventArgs e)
        {
            //Beep(850, 1500);
            musicFun.Stop();
        }



        internal void StopTest()
        {
            foreach (Interpreter i in interp)
            {
                i.Stop();
            }
            musicFun.Stop();
        }

        #endregion
    }
}
